﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Snowflake.Common;

namespace Snowflake.Entity
{
    public abstract partial class EntityObject<TEntity>
    {
        internal Dictionary<string, object> GetValuesForDbUpdate()
        {
            Dictionary<string, object> result = new Dictionary<string, object>();

            IEnumerable<IRestorableValue> changedValues = this._RestorableValueManager.GetChangedValues();

            foreach (IRestorableValue field in changedValues)
            {
                Type fieldType = field.GetType();
                if(fieldType.IsGenericType)
                {
                    fieldType = fieldType.GetGenericTypeDefinition();
                    
                    if (fieldType == typeof(EntityField<>))
                        result.Add(field.Name, field.Value);                
                }
            }

            return result;
        }
        /// <summary>
        /// Class that wrapps the column property' value
        /// </summary>
        /// <typeparam name="TValue">Type of the column</typeparam>
        protected class EntityField<TValue> : RestorableValue<TValue>
        {
            private EntityObject<TEntity> _EntityObject;

            internal EntityField(EntityObject<TEntity> entityObject, string columnName, TValue value)
                : base(columnName, value)
            {
                this._EntityObject = entityObject;
                entityObject.RestorableValueManager.Add(this);
            }

            internal EntityField(EntityObject<TEntity> entityObject, string columnName)
                : this(entityObject, columnName, default(TValue))
            {
            }

            private bool CheckEntityObjectState()
            {
                if (this._EntityObject._State == EntityObjectState.Deleted)
                    throw new InvalidOperationException("'" + this._Name + "' cannot be changed, because the object is in deleted state.");

                return true;
            }

            /// <summary>
            /// Value of the property
            /// </summary>
            public override TValue Value
            {
                set
                {
                    if (!Object.Equals(value, this._Value))
                    {
                        if (this.CheckEntityObjectState())
                        {
                            if (!this._EntityObject.IsValidPropertyValue<TValue>(this._Name, value))
                                return;

                            PropertyChangingEventArgs propChangingEventArgs = new PropertyChangingEventArgs(this._Name, this._Value, value);
                            this._EntityObject.PropertyChanging(this._EntityObject, propChangingEventArgs);

                            if (propChangingEventArgs.Cancel)
                                return;

                            if (!this._HasChanges)
                            {
                                EntityObjectState state = this._EntityObject._State;

                                if (state == EntityObjectState.Modified || state == EntityObjectState.Unchanged)
                                {
                                    this._OriginalValue = this._Value;
                                    this._HasChanges = true;

                                    if (state == EntityObjectState.Unchanged)
                                        this._EntityObject._State = EntityObjectState.Modified;
                                }
                            }
                        }

                        this._Value = value;

                        this._EntityObject.PropertyChanged(this._EntityObject, new PropertyChangedEventArgs(this._Name, value));
                    }
                }
                get
                {
                    this.CheckEntityObjectState();

                    return this._Value;
                }
            }
        }
    }
}
